/*
 * This file is part of Ember.
 *
 * Ember is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Ember is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Ember.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright (C) Grant Tyra 2010
 * granttyra@gmail.com
*/

#include "ember_dictionary.h"
#include "ember_string.h"
#include <stdlib.h>
#include <string.h>

EmberDictionary *EmberDictionaryCreate(void) {
	int i = 0;
	EmberDictionary *dictionary = malloc(sizeof(EmberDictionary));

	dictionary->size = 10;
	dictionary->values = calloc(dictionary->size, sizeof(EmberDictionaryMapping*));

	for (i = 0; i < dictionary->size; i++) {
		dictionary->values[i] = NULL;
	}

	return dictionary;
}

void EmberDictionaryDestroy(EmberDictionary *dictionary) {
	int i = 0;
	EmberDictionaryMapping *entry = NULL;

	if (dictionary == NULL) {
		return;
	}

	for (i = 0; i < dictionary->size; i++) {
		entry = dictionary->values[i];

		if (entry == NULL) {
			continue;
		}
		
		EmberStringDestroy(entry->key);
		free(entry);
	}

	free(dictionary->values);
	free(dictionary);
}

void *EmberDictionaryGet(EmberDictionary *dictionary, const char *key) {
	int hash = 0;
	int i = 0;
	EmberDictionaryMapping *entry = NULL;

	if (dictionary == NULL || key == NULL) {
		return NULL;
	}

	hash = EmberStringHash(key) % dictionary->size;
	i = hash;

	do {
		entry = dictionary->values[i];

		if (entry != NULL && strcmp(entry->key, key) == 0) {
			return entry->value;
		}

		i++;

		if (i >= dictionary->size) {
			i = 0;
		}
	} while (i != hash);

	return NULL;
}

void dictionary_resize(EmberDictionary *dictionary, int size) {
	int i = 0;
	dictionary->values = realloc(dictionary->values, size * sizeof(EmberDictionaryMapping));

	for (i = dictionary->size; i < size; i++) {
		dictionary->values[i] = NULL;
	}

	dictionary->size = size;
}

void EmberDictionaryRemove(EmberDictionary *dictionary, const char *key) {
	int hash = 0;
	int i = 0;
	EmberDictionaryMapping *entry = NULL;

	hash = EmberStringHash(key) % dictionary->size;
	i = hash;

	do {
		entry = dictionary->values[i];

		if (entry != NULL && strcmp(entry->key, key) == 0) {
			EmberStringDestroy(entry->key);
			free(entry);
			dictionary->values[i] = NULL;
			return;
		}

		i++;

		if (i >= dictionary->size) {
			i = 0;
		}
	} while (i != hash);
}

void EmberDictionaryPut(EmberDictionary *dictionary, const char *key, void *value) {
	int hash = 0;
	int i = 0;
	EmberDictionaryMapping *entry = NULL;

	hash = EmberStringHash(key) % dictionary->size;
	i = hash;

	do {
		entry = dictionary->values[i];

		if (entry == NULL) {
			entry = malloc(sizeof(EmberDictionaryMapping));
			entry->key = EmberStringCopy(key);
			entry->value = value;
			dictionary->values[i] = entry;
			return;
		}

		if (strcmp(entry->key, key) == 0) {
			entry->value = value;
			return;
		}

		i++;

		if (i >= dictionary->size) {
			i = 0;
		}
	} while (i != hash);

	dictionary_resize(dictionary, dictionary->size * 2);
	EmberDictionaryPut(dictionary, key, value);
}

void EmberDictionaryValues(EmberDictionary *dictionary, EmberList *values) {
	int i = 0;
	EmberDictionaryMapping *entry = NULL;

	for (i = 0; i < dictionary->size; i++) {
		entry = dictionary->values[i];

		if (entry != NULL) {
			EmberListAdd(values, entry->value);
		}
	}
}

void EmberDictionaryKeys(EmberDictionary *dictionary, EmberList *keys) {
	int i = 0;
	EmberDictionaryMapping *entry = NULL;

	for (i = 0; i < dictionary->size; i++) {
		entry = dictionary->values[i];

		if (entry != NULL) {
			EmberListAdd(keys, EmberStringCopy(entry->key));
		}
	}
}
